Rust: Smart Pointer
Box<T>
Box stores data on the heap rather than the stack.
Usecase
recursive structure like cons list
Overall size of cons list cannot be decided a priori.
Example
code: box_example.rs
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));
}
Rc<T>
Rc shares data between multiple parts of your program for reading only.
Usecase
graph structure
One vertex can be pointed from two or more edges.
Example
code: rc_example.rs
fn main() {
let a = Rc::new(1);
println!("{}", Rc::strong_count(&a)); // -> 1
{
let b = Rc::clone(&a);
println!("{}", Rc::strong_count(&a)); // -> 2
println!("{}", Rc::strong_count(&b)); // -> 2
}
println!("{}", Rc::strong_count(&a)); // -> 1
}
Note
a.clone() is sometimes also available instead of Rc::clone(a) but not efficient in that deep copy is usually done.
RefCell<T>
RefCell mutates data even when there are immutable references to that data (which is called Interior mutability).
Usecase
Mock object
If the function of production code takes immutable self as its parameter, mock object cannot do mutating operatons like recording what happens during a test without RefCell.
Example
code: refcell_example.rs
struct RefCellList {
inner: RefCell<Vec<i32>>,
}
impl RefCellList {
fn new() -> RefCellList {
RefCellList { inner: RefCell::new(vec![]) }
}
fn add(&self, num: i32) {
self.inner.borrow_mut().push(num);
}
}
fn main() {
let list = RefCellList::new();
list.add(1);
list.add(2);
println!("{:?}", list.inner.borrow()); // -> 1, 2 }
Note
borrow_mut returns the smart pointer type RefMut<T>
borrow returns the smart pointer type Ref<T>
References